// 题意：和poj1743一模一样
//
// 题解：poj标准库容器动态内存操作慢的一比，不开优化都去XX。
//       改成静态就过了...还试了一下输入输出外挂，然并卵。
//       openjudge上倒是跑的飞快...
//
// run: time $exec < input
#include <cstdio>
#include <algorithm>
#include <vector>
#include <utility>

int const inf = 1 << 28;
int const maxn = 40007;
bool centroid[maxn];
int subtree_size[maxn];
int n, m, k, ans;

typedef std::pair<int, int> node_type;
typedef std::vector<node_type> adj_edge;
typedef adj_edge::iterator edge_iter;

node_type graph[maxn][8];

int calc_subtree_size(int u, int parent)
{
	int sum = 1;
	for (int i = 1; i <= graph[u][0].first; i++) {
		int v = graph[u][i].first;
//	for (edge_iter it = graph[u].begin(); it != graph[u].end(); ++it) {
//		int v = it->first;
		if (centroid[v] || parent == v) continue;
		sum += calc_subtree_size(v, u);
	}
	return subtree_size[u] = sum;
}

std::pair<int, int> get_center(int u, int parent, int all)
{
	std::pair<int, int> center(inf, -1);
	int sum = 1, max_sub = 0;
//	for (edge_iter it = graph[u].begin(); it != graph[u].end(); ++it) {
//		int v = it->first;
	for (int i = 1; i <= graph[u][0].first; i++) {
		int v = graph[u][i].first;
		if (centroid[v] || parent == v) continue;
		max_sub = std::max(max_sub, subtree_size[v]);
		sum += subtree_size[v];
		center = std::min(center, get_center(v, u, all));
	}
	max_sub = std::max(max_sub, all - sum);
	return std::min(center, std::make_pair(max_sub, u));
}

void calc_dis_to_center(int u, int parent, int dis, std::vector<int> & count)
{
	count.push_back(dis);
	for (int i = 1; i <= graph[u][0].first; i++) {
//	for (edge_iter it = graph[u].begin(); it != graph[u].end(); ++it) {
//		int v = it->first, c = it->second;
		int v = graph[u][i].first, c = graph[u][i].second;
		if (centroid[v] || parent == v) continue;
		calc_dis_to_center(v, u, dis + c, count);
	}
}

int calc_pair(std::vector<int> & count)
{
	std::sort(count.begin(), count.end());
	int tot = 0, len = count.size();
	for (int l = 0, r = len - 1; l < r; l++) {
		for (; l < r && count[l] + count[r] > k; r--);
		tot += r - l;
	}
	return tot;
}

void divide_and_conquer_for_tree(int u)
{
	calc_subtree_size(u, -1);
	int center = get_center(u, -1, subtree_size[u]).second;
	centroid[center] = true;

	for (int i = 1; i <= graph[center][0].first; i++) {
//	for (edge_iter it = graph[center].begin(); it != graph[center].end(); ++it) {
//		int v = it->first;
		int v = graph[center][i].first;
		if (centroid[v]) continue;
		divide_and_conquer_for_tree(v);
	}

	std::vector<int> count(1);
//	for (edge_iter it = graph[center].begin(); it != graph[center].end(); ++it) {
	for (int i = 1; i <= graph[center][0].first; i++) {
		//int v = it->first, c = it->second;
		int v = graph[center][i].first, c = graph[center][i].second;
		if (centroid[v]) continue;
		std::vector<int> tmp_count;
		calc_dis_to_center(v, center, c, tmp_count);
		ans -= calc_pair(tmp_count);
		count.insert(count.end(), tmp_count.begin(), tmp_count.end());
	}
	ans += calc_pair(count);
	centroid[center] = false;
}


int main()
{
	std::scanf("%d%d", &n, &m);
	for (int i = 0, x, y; i < m; i++) {
		node_type tmp;
		//scan(x); scan(y); scan(tmp.second);
		std::scanf("%d%d%d", &x, &y, &tmp.second);
//		std::printf("%d %d %d \n", x, y, tmp.second);
		std::getchar(); std::getchar();
		x--; y--;
		tmp.first = y; graph[x][ ++graph[x][0].first ] = tmp;
		tmp.first = x; graph[y][ ++graph[y][0].first ] = tmp;
	}
	std::scanf("%d", &k);
	//scan(k);

	ans = 0;
	divide_and_conquer_for_tree(0);
	std::printf("%d\n", ans);
}

